﻿// Copyright (c) 2012 Mokah Nnamezie & Andrew Cooper
// Neo4Net graph database - http://neo4net.codeplex.com
//
// This file is part of Neo4Net - a .Net port of the Neo4j graph database
//
// Neo4Net is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

namespace Neo4Net.Kernel.Impl.Core
{
    using System;
    using Neo4Net.Compat.Atomic;
    using Neo4Net.Kernel.Impl.Nioneo.Store;

    public partial class JumpingIdGeneratorFactory
    {
        private class JumpingIdGenerator : IIdGenerator
        {
            private readonly AtomicInt64 nextId = new AtomicInt64();
            private readonly int sizePerJump;
            private int leftToNextJump;
            private long highBits = 0;

            public JumpingIdGenerator(int sizePerJump)
            {
                this.sizePerJump = sizePerJump;
                leftToNextJump = sizePerJump / 2;
            }

            public long NextId
            {
                get
                {
                    long result = TryNextId();
                    if (--leftToNextJump == 0)
                    {
                        leftToNextJump = sizePerJump;
                        nextId.Value = (0xFFFFFFFFL | (highBits++ << 32)) - sizePerJump / 2 + 1;
                    }
                    return result;
                }
            }

            private long TryNextId()
            {
                long result = nextId.GetAndIncrement();
                if (result == IdGeneratorImpl.IntegerMinusOne)
                {
                    result = nextId.GetAndIncrement();
                    leftToNextJump--;
                }
                return result;
            }

            public IdRange NextIdBatch(int size)
            {
                throw new NotSupportedException();
            }

            public long HighId
            {
                get { return nextId.Value; }
                set { nextId.Value = value; }
            }

            public void FreeId(long id)
            {
            }

            public void Close(bool shutdown)
            {
            }

            public long NumberOfIdsInUse
            {
                get { return nextId.Value; }
            }

            public long DefragCount
            {
                get { return 0; }
            }

            public void Delete()
            {
            }
        }
    }
}
